// Deploys a contract onto the specified network and generates 
// transactions in batches to this contract 
// Each transaction is submitted from a new account
// usage: node mockTransactions.js requestsPerBatch rpcEndpoint

const Web3 = require('web3');
const ethereumjs = require('ethereumjs-tx');
const wallet = require('ethereumjs-wallet');
const crypto = require('crypto');

const sendMethod = 'sendRawTransaction';
const imei = '0x' + crypto.randomBytes(32).toString('hex');

var web3 = null;
var running = false;
var ethRequests = [];
var rawTx = {
  chainId: 5,
  nonce: 0,
  action: 1,
  imei: imei,
};

module.exports = (opt) => {
  var batch = Number(opt.batch) || 1;
  var step = Number(opt.step) || 0;
  var gap = opt.gap || 1000;
  var rpc = opt.rpc;
  web3 = new Web3(new Web3.providers.HttpProvider(rpc));

  return () => {
    batch += step;
    var intervalId = setInterval(batchRequests, gap, batch); // instead of tx/s to tx/ms per batch
    return [() => clearInterval(intervalId), batch];
  }
}

function batchRequests(batch) {
  if (!running) {
    running = true;
    for (var i = 0; i < batch; i++) {
        var privateKey = wallet.generate().getPrivateKey();
        ethRequests.push(ethRequest(privateKey));
    }
    Promise.all(ethRequests).then(() => running = false);
  }
}

function ethRequest(privateKey) {
  return new Promise((resolve, reject) => {
    var tx = new ethereumjs(rawTx);
    tx.sign(privateKey);
    var raw = '0x' + tx['serialize']().toString('hex');

    web3.okey[sendMethod](raw, (txErr, txHash) => {
      if (!txErr) {
        resolve(txHash);
      } else {
        console.log('Error: ' + txErr);
        return reject('Error: ' + txErr);
      }
    });
  });
}